package io.github.yotta.notice.sms.aliyun.channel;

import com.alibaba.fastjson.JSON;
import com.aliyun.dysmsapi20170525.Client;
import com.aliyun.dysmsapi20170525.models.SendSmsRequest;
import com.aliyun.dysmsapi20170525.models.SendSmsResponse;
import com.aliyun.dysmsapi20170525.models.SendSmsResponseBody;
import com.aliyun.teaopenapi.models.Config;
import com.aliyun.teautil.models.RuntimeOptions;
import io.github.yotta.common.api.model.Response;
import io.github.yotta.notice.common.dto.NoticeSendResponse;
import io.github.yotta.notice.sms.aliyun.AliSmsApiConstants;
import io.github.yotta.notice.sms.aliyun.token.AliSmsToken;
import io.github.yotta.notice.sms.aliyun.token.AliSmsTokenProvider;
import io.github.yotta.notice.sms.common.SmsNoticeChannel;
import io.github.yotta.notice.sms.common.SmsNoticeRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;

/**
 * @author yotta
 * @date 2023/4/30 14:33
 * 阿里云短息发送渠道
 */
@Slf4j
public class AliSmsNoticeChannel implements SmsNoticeChannel {

    private static final String PHONE_NUMBER_JOINER = ",";

    private static final String DATE_FORMAT_PATTERN = "yyyy-MM-dd HH:mm:ss";

    private final AliSmsTokenProvider aliSmsTokenProvider;

    public AliSmsNoticeChannel(AliSmsTokenProvider aliSmsTokenProvider) {
        this.aliSmsTokenProvider = aliSmsTokenProvider;
    }

    @Override
    public Response<NoticeSendResponse> send(SmsNoticeRequest request) {
        try {
            final Client aliSmsClient = getAliSmsClient(request.getTenantId());
            SendSmsRequest sendSmsRequest = convertAliSmsRequest(request);
            final SendSmsResponse sendSmsResponse = aliSmsClient
                    .sendSmsWithOptions(sendSmsRequest, RuntimeOptions.build(request.getOptions()));
            return parseAliResponse(sendSmsResponse);
        } catch (Exception e) {
            log.error("send sms error cause by [{}]", e.getMessage(), e);
            return Response.fail(e.getMessage());
        }

    }

    protected Client getAliSmsClient(String tenantId) throws Exception {
        final AliSmsToken token = aliSmsTokenProvider.findToken(tenantId);
        Config config = new Config()
                // 必填，您的 AccessKey ID
                .setAccessKeyId(token.getAccessKey())
                // 必填，您的 AccessKey Secret
                .setAccessKeySecret(token.getAccessSecret())
                .setRegionId(token.getRegionId())
                .setEndpoint(token.endPoint());
        return new Client(config);
    }

    private SendSmsRequest convertAliSmsRequest(SmsNoticeRequest smsNoticeDto) {
        return new SendSmsRequest()
                .setPhoneNumbers(joinPhoneNumbersWithPhoneNumberJoiner(smsNoticeDto.getReceivers()))
                .setSignName(smsNoticeDto.getSignName())
                .setTemplateParam(JSON.toJSONString(smsNoticeDto.getTemplateParam()))
                .setTemplateCode(smsNoticeDto.getTemplateCode());
    }

    /**
     * 解析阿里云返回成功的
     * Sat, 29 Apr 2023 07:50:09 GMT
     */
    private Response<NoticeSendResponse> parseAliResponse(SendSmsResponse sendSmsResponse) {
        final SendSmsResponseBody body = sendSmsResponse.getBody();
        if (AliSmsApiConstants.OK.equalsIgnoreCase(body.getCode())) {
            final NoticeSendResponse sendResponse = NoticeSendResponse.builder()
                    .outId(body.getBizId())
                    .sendTime(parseTime(sendSmsResponse))
                    .build();
            return Response.ok(sendResponse);
        } else {
            return Response.fail(body.getMessage());
        }

    }

    /**
     * 时间格式转换
     * 阿里api返回的时间格式为：Sat, 29 Apr 2023 07:50:09 GMT 国内需要加8小时
     */
    private String parseTime(SendSmsResponse sendSmsResponse) {
        String sourceTime = null;
        try {
            final Map<String, String> headers = sendSmsResponse.getHeaders();
            if (MapUtils.isNotEmpty(headers)) {
                sourceTime = headers.get(AliSmsApiConstants.RESPONSE_HEADER_DATE);
                if (StringUtils.isNotEmpty(sourceTime)) {
                    final LocalDateTime parse = LocalDateTime.parse(sourceTime, DateTimeFormatter.RFC_1123_DATE_TIME);
                    return parse.plusHours(8).format(DateTimeFormatter.ofPattern(DATE_FORMAT_PATTERN));
                }
            }
        } catch (Exception e) {
            log.warn("send parse error; sourceTime: [{}]", sourceTime);
        }
        return null;
    }

    private String joinPhoneNumbersWithPhoneNumberJoiner(List<String> phoneNumbers) {
        if (CollectionUtils.isNotEmpty(phoneNumbers)) {
            return String.join(PHONE_NUMBER_JOINER, phoneNumbers);
        }
        return "";
    }
}
